Skip to content

Conversation

@dbaluta
Copy link
Collaborator

@dbaluta dbaluta commented Oct 13, 2025

Remove any containers from the free container list so that we don't keep pointers to containers that are no longer used and will be freed when container chunks are released below.

Leaving those nodes in the free container list would cause use-after-free on subsequent allocations.

While at it, make sure all resource lists are reset.

Copilot AI review requested due to automatic review settings October 13, 2025 07:38
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes a use-after-free vulnerability in the module adapter's generic resource management by properly cleaning up free container lists and resetting resource accounting.

  • Remove containers from the free container list before freeing container chunks to prevent dangling pointers
  • Reset all resource lists and heap usage accounting to ensure clean state after freeing resources

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@dbaluta dbaluta force-pushed the fix_use_after_free branch 2 times, most recently from 53da97f to 01e4e87 Compare October 13, 2025 07:41
Copy link
Contributor

@tmleman tmleman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Fails in CI looks like env issue, lets wait for re-run.

lyakh
lyakh previously requested changes Oct 15, 2025
Copy link
Collaborator

@lyakh lyakh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand it correctly, that this is addressing a case, when "chunks" of containers are freed, then they happen to be allocated again and the new owner finds old data in them? If that my understanding is correct, then I don't think this is a right approach. If we want to do this, then we'd have to memset(0) all memory buffers before freeing.

@dbaluta
Copy link
Collaborator Author

dbaluta commented Oct 16, 2025

@lyakh No.

Container chunks have allocated up to 16 containers. We store references to these containers in the free containers list.

Then when we free a chunk, we free the memory for this 16 containers but we do not remove the references from the containers free list. This means that the containers list will contain some pointers to freed memory.

Next time we allocate a container chunk we allocate again new 16 containers chunks and we place references to this new containers in the free containers list. But this list already has references to the older containers (because we never removed them from free container list).

What happens is that at some point one of the older references is picked to be used and we access freed memory.

using memset won't help.

@kv2019i kv2019i requested a review from jsarha October 16, 2025 12:11
Copy link
Collaborator

@kv2019i kv2019i left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent catch @dbaluta ! @jsarha is not today available to comment, but I think the original implementation did not expect the module to be used again after mod_free_all(). In module_adapter_free(), there's a call to mod_free_all() but afterwards the module resources are also freed. But I now see in cadence.c, mod_free_all() is called in multiple places, including cadence_codec_reset(). And yeah, mod_free_all() does not leave the containers in proper state.

list_init(&res->res_list);
list_init(&res->free_cont_list);
list_init(&res->cont_chunk_list);
res->heap_usage = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe call to "mod_resource_init()" here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, will send a new version asap.

@kv2019i
Copy link
Collaborator

kv2019i commented Oct 16, 2025

@dbaluta @lgirdwood I think we need this fix in stable-v2.14 as well.

@dbaluta dbaluta force-pushed the fix_use_after_free branch from 01e4e87 to 68b7672 Compare October 16, 2025 14:48
@dbaluta
Copy link
Collaborator Author

dbaluta commented Oct 16, 2025

Changes since v1:

  • added mod_resource_init as per @kv2019i feedback.

I will backport it to v2.14 once this is merged.

@dbaluta dbaluta force-pushed the fix_use_after_free branch from 68b7672 to fb17ec9 Compare October 17, 2025 06:28
@lyakh
Copy link
Collaborator

lyakh commented Oct 17, 2025

What happens is that at some point one of the older references is picked to be used and we access freed memory.

@dbaluta right, yes, thanks for explaining. But usually mod_free_all() is only called when the module is freed, so no new allocations should be performed there? I see one "abuse" though - in cadence.c, where mod_free_all() is called durinig a reset... Is that what you're referring to? Then it might be a problem. Not sure about the current state, but in the future I'd expect also the infrastructure to allocate per-module memory using the mod_alloc*() API... But maybe I'm wrong. I'll remove my "request for change" but there's more to clarify here... Thanks!

@lyakh lyakh dismissed their stale review October 17, 2025 06:29

(partially) clarified

Factor out resource initialization so that it can be reused.
While at it get rid of md variable.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Remove any containers from the free container list so that
we don't keep pointers to containers that are no longer used
and will be freed when container chunks are released below.

Leaving those nodes in the free container list would cause
use-after-free on subsequent allocations.

While at it, make sure all resource lists are reset.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Copy link
Contributor

@jsarha jsarha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some room for optimization, but looks good otherwise.

struct module_resource *container =
container_of(list, struct module_resource, list);

list_item_del(&container->list);
Copy link
Contributor

@jsarha jsarha Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be no need to do this anymore, after the mod_resource_init(mod) call was added. It will reinitialize &res->free_cont_list at the end of the function. No need to remove the containers one by one.

container_of(list, struct module_resource, list);

free_contents(mod, container);
list_item_del(&container->list);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually also this list_item_del()-call could be removed now that &res->res_list is also reinitialized at the end of the function when mod_resource_init() is called.

@kv2019i
Copy link
Collaborator

kv2019i commented Oct 17, 2025

@dbaluta Feel free to either address Jyri's suggestions, or to just go ahead and merge this. If needed @jsarha can do a follow-up PR to optimize the the free_all implementation.

Copy link
Member

@lgirdwood lgirdwood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack - this will be needed for v2.14

@dbaluta dbaluta merged commit 259c32b into thesofproject:main Oct 19, 2025
39 of 45 checks passed
@dbaluta
Copy link
Collaborator Author

dbaluta commented Oct 19, 2025

@kv2019i merged this as it is, as it is following a logical cleanup of the lists, in reverse wrt the init part.

@jsarha please send a follow up with the simplification if you think it is necessary.

@jsarha
Copy link
Contributor

jsarha commented Oct 20, 2025

@kv2019i merged this as it is, as it is following a logical cleanup of the lists, in reverse wrt the init part.

@jsarha please send a follow up with the simplification if you think it is necessary.

@dbaluta the optimize PR is here: #10316

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants